<!--/**
* @author xuyh0817
* @email xuyh0817@foxmail.com
* @date 2022-02-16 14:58
* @version 2.0.0
* @doc todo
* @website todo
* @remark  如果要分发源码，需在本文件顶部保留此文件头信息！！
*/
-->

<template>
  <div class="x-upload-file-container">
    <file-item
        v-for="item in filterFileList"
        :key="item.fileId"
        :file="item"
        :preview="preview"
        :download="download"
        :remove="remove"
        @remove="removeHandler"
        @preview="previewHandler"
        @download="downloadHandler"
    />
    <template v-if="preview">
      <a-empty v-if="fileList.length === 0" :description="isImage ?'没有上传图片' : '没有上传文件'"/>
    </template>
    <template v-else>
      <a-spin :spinning="loading" tip="文件上传中" class="x-upload-btn">
        <a-upload
            list-type="picture-card"
            :file-list="fileList"
            :remove="removeHandler"
            :accept="accept"
            :show-upload-list="false"
            :custom-request="customRequestHandler"
            @preview="previewHandler"
            @change="changeHandler"
        >
          <div v-if="fileList.length < count">
            <i class="fal fa-plus"></i>
            <div class="ant-upload-text">
              上传
            </div>
          </div>
        </a-upload>
      </a-spin>
    </template>

    <a-modal
        centered
        destroy-on-close
        :visible="file.show"
        :footer="null"
        :width="fileIsPdf(file.type) ? '90%': '600px'"
        :title="file.name + '预览'"
        @cancel="file.show = false"
    >
      <img v-if="fileIsImage(file.type) && !!file.preview" :alt="file.name" class="x-update-image-container"
           :src="file.preview"/>
      <video
          v-if="fileIsMp4(file.type) && !!file.preview"
          :alt="file.name"
          class="x-upload-video-container"
          :src="file.preview"
          controls="controls"
      ></video>
      <a-spin v-if="fileIsPdf(file.type)" :spinning="file.loading" tip="正在加载中...">
        <embed
            v-if="!!file.preview"
            :src="file.preview"
            type="application/pdf"
            class="x-upload-pdf-container"
        />
      </a-spin>
    </a-modal>

  </div>
</template>

<script>
import {COMPONENT_TYPE, CUSTOM_EVENT_TYPE, RENDER_OPTIONS} from '../../constants'
import ComponentMixin from '../../XRenderMixins/XRenderComponentMixin'
import FileItem from './Item'
import {indexOf, toLower} from 'lodash'

export default {
  name: COMPONENT_TYPE.UPLOAD_FILE + 'Base',
  mixins: [ComponentMixin],
  inject: ['XAntForm'],
  components: {
    FileItem
  },
  props: {
    isImage: {
      type: Boolean,
      default: false
    },
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      loading: false,
      file: {
        show: false,
        preview: '',
        name: ''
      },
      // 文件列表
      fileList: []
    }
  },
  computed: {
    filterFileList: {
      get() {
        const {fileList} = this
        return fileList.filter(item => item.status === 'done')
      }
    },
    count: {
      get() {
        const {count} = this.attrs
        return count || 9
      }
    },
    preview: {
      get() {
        const {preview} = this.attrs
        return !!preview
      }
    },
    accept: {
      get() {
        const {accept, isImage} = this.attrs
        return isImage ? (accept || '.jpg, .png,.bmp,.gif,jpeg') : (accept || '.xls,.xlsx,.doc,.docx,.ppt,.pptx,.pdf')
      }
    },
    download: {
      get() {
        const {download} = this.attrs
        return !!download
      }
    },
    remove: {
      get() {
        const {remove} = this.attrs
        return !!remove
      }
    },
    multiple: {
      get() {
        const {multiple} = this.attrs
        return !!multiple
      }
    }
  },
  watch: {
    attrs: {
      immediate: true,
      deep: true,
      handler() {
        this.initFileList()
      }
    }
  },
  methods: {
    getMethod(name) {
      const {$XRenderOptions: options} = this
      // 全局配置的方法
      if (options.hasOwnProperty(name) && options[name] instanceof Function) {
        return options[name]
      }
      this.$message.error(`未配置${name}方法，请确认`)
      return undefined
    },
    previewHandler(file) {
      const {file: dataFile, fileIsPdf} = this
      dataFile.type = file.type
      dataFile.name = file.name
      dataFile.show = true
      if (fileIsPdf(file.type)) {
        dataFile.preview = ''
        const doViewPdf = this.doRemoveFile(file)
        if (!!doViewPdf) {
          dataFile.loading = true
          doViewPdf(file).then((res) => {
            dataFile.preview = window.URL.createObjectURL(
                new Blob([res], {type: 'application/pdf'})
            )
            dataFile.loading = false
          }).catch(() => {
            dataFile.loading = false
            this.$message.error(
                'pdf文件读取失败，无法预览，可点击文件名称下载预览'
            )
          })
        }
      } else {
        dataFile.preview = file.url
      }
    },
    doViewPdf(file) {
      const method = this.getMethod(RENDER_OPTIONS.VIEW_PDF)
      if (!!method) {
        return method(file)
      }
      return undefined
    },
    downloadHandler(file) {
      const aNode = document.createElement('a')
      aNode.download = file.name
      aNode.href = file.url
      aNode.style.display = 'none'
      document.body.appendChild(aNode)
      aNode.click()
      document.body.removeChild(aNode)
    },
    removeHandler(file) {
      const {fileList} = this
      if (fileList.length === 0) {
        return
      }
      this.$confirm({
        title: '温馨提示',
        content: `您确定要删除【 ${file.name} 】吗？`,
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          const doRemoveFile = this.doRemoveFile(file)
          if (!!doRemoveFile) {
            doRemoveFile.then(() => {
              const index = fileList.findIndex(item => item.fileId === file.fileId)
              fileList.splice(index, 1)
              this.$emit(CUSTOM_EVENT_TYPE.CUSTOM_EVENT, {
                type: CUSTOM_EVENT_TYPE.REMOVE_EVENT,
                file
              })
            })
          }
        },
        onCancel: () => {
        }
      })
    },
    doRemoveFile(file) {
      const method = this.getMethod(RENDER_OPTIONS.REMOVE_FILE)
      if (!!method) {
        return method(file)
      }
      return undefined
    },
    changeHandler({fileList: list}) {
      const {fileList} = this
      const length = fileList.length
      fileList.splice(0, length, ...list)
      this.$emit(CUSTOM_EVENT_TYPE.CUSTOM_EVENT, {
        type: CUSTOM_EVENT_TYPE.UPLOAD_CHANGE_EVENT,
        fileList
      })
    },
    // 附件上传
    customRequestHandler(data) {
      const {file, onSuccess, onError} = data
      const that = this
      const {value, formItem} = this

      const success = (fileItem) => {
        const file = that.itemPostProcessor(fileItem)
        // 完成
        onSuccess()
        that.fileList.push(file)
        that.fileList.map((v, i) => {
          if (v.percent === 0) {
            that.fileList.splice(i, 1)
          }
        })
        return file
      }

      // 上传
      const doUploadFile = this.doUploadFile({file, value, prop: formItem.prop})
      if (!!doUploadFile) {
        this.loading = true
        doUploadFile.then((fileItem) => {
          this.loading = false
          const fileData = success(fileItem)
          this.$emit(CUSTOM_EVENT_TYPE.CUSTOM_EVENT, {
            type: CUSTOM_EVENT_TYPE.UPLOAD_EVENT,
            file: fileData
          })
        }).catch(() => {
          this.loading = false
          onError()
        })
      }
    },
    doUploadFile(data) {
      const method = this.getMethod(RENDER_OPTIONS.UPLOAD_FILE)
      if (!!method) {
        return method(data)
      }
      return undefined
    },
    doListFile(prop, value) {
      const method = this.getMethod(RENDER_OPTIONS.LIST_FILE)
      if (!!method) {
        return method({prop, value})
      }
      return undefined
    },
    initFileList() {
      const {fileList, itemPostProcessor, value, formItem} = this
      const doListFile = this.doListFile(formItem.prop, value)
      if (!!doListFile) {
        doListFile.then((data) => {
          for (const file of data) {
            fileList.push(itemPostProcessor(file))
          }
        })
      }
    },
    itemPostProcessor(item) {
      const previewUrl = this.itemDataConvert(item)
      return {
        ...item,
        uid: 0 - Date.now(),
        status: 'done',
        percent: 100,
        preview: previewUrl,
        canPreview: item.canPreview
      }
    },
    // 对附件数据进行处理
    itemDataConvert(item) {
      const {fileIsImage, fileIsMp4} = this
      const fileTypes = ['ppt', 'pptx', 'doc', 'docx', 'xls', 'xlsx', 'rar', 'zip', '7z', 'txt']
      item.canPreview = false
      const fileType = item.type
      if (fileIsImage(fileType)) {
        item.canPreview = true
        return item.url
      } else if (fileIsMp4(fileType)) {
        item.canPreview = true
        return require(`./icons/${fileType}.png`)
      } else if (!!fileType && fileTypes.includes(toLower(fileType))) {
        return require(`./icons/${fileType}.png`)
      } else if (this.fileIsPdf(fileType)) {
        item.canPreview = true
        return require('./icons/pdf.png')
      }
      return require('./icons/unknow.png')
    },
    fileIsImage(type) {
      const imageFileTypes = ['jpg', 'png', 'jpeg', 'bmp', 'gif']
      return !!type && indexOf(imageFileTypes, toLower(type)) > -1
    },
    fileIsMp4(type) {
      return !!type && toLower(type) === 'mp4'
    },
    fileIsPdf(type) {
      return !!type && toLower(type) === 'pdf'
    },
  }
}
</script>

<style scoped lang="css">
.x-upload-file-container {
  width: 100%;
  display: flex;
  flex-flow: row wrap;
}

.x-upload-btn {
  height: 125px;
  width: 104px;
  padding-bottom: 21px;
}

/deep/ .ant-modal-body {
  padding: 8px !important;
  display: flex;
  width: 100%;
  flex-flow: column nowrap;
  justify-content: center;
  min-height: 400px;
}

.x-upload-pdf-container {
  width: 100%;
  height: calc(100vh - 150px);
}

.x-upload-video-container {
  width: 100%;
  height: 400px;
  object-fit: inherit;
}

.x-update-image-container {
  width: 100%;
  height: 400px;
}
</style>
